package PartEdgeDemo;

import y.base.Edge;
import y.base.Node;
import y.base.NodeCursor;
import y.base.NodeMap;
import y.layout.Layouter;
import y.layout.circular.SingleCycleLayouter;
import y.view.Graph2D;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: zielke
 * Date: 9/30/11
 * Time: 10:57 AM
 * To change this template use File | Settings | File Templates.
 */
public class BipartiteCreater {
  final int outerNodes;
  final int innerNodes;
  final Graph2D g;
  final double radius;

  public BipartiteCreater(int outerNodes, int innerNodes, Graph2D g, int radius) {
    this.outerNodes = outerNodes;
    this.innerNodes = innerNodes;
    this.g = g;
    if(radius == 0)
      this.radius = g.getDefaultNodeRealizer().getHeight() * outerNodes;
    else
      this.radius = g.getDefaultNodeRealizer().getHeight() * radius;
  }

  public Graph2D create(){
    g.clear();
    ArrayList<Node> outer = new ArrayList<Node>();
    for(int i=0;i<outerNodes;i++)
      outer.add(g.createNode(0, 0, String.valueOf(g.nodeCount())));

    ArrayList<Node> inner = new ArrayList<Node>();
    for(int i=0;i<innerNodes;i++)
      inner.add(g.createNode(radius, radius, String.valueOf(g.nodeCount())));

    connectBipartite(outer, inner);
    layoutBipartite(outer, inner);
    
    Node[] nodeArray = g.getNodeArray();
    for (int i = 0; i < nodeArray.length; i++) 
    	g.getRealizer(nodeArray[i]).setSize(1, 1);
		
	
    return g;
  }

  private void connectBipartite(List<Node> outer, List<Node> inner) {
    for(Node nOut:outer){
      for(Node nIn:inner){
        g.createEdge(nOut, nIn);
      }
    }
  }

  private void layoutBipartite(List<Node> outer, List<Node> inner) {
    SingleCycleLayouter layouter = new SingleCycleLayouter();
    layouter.setSubgraphLayouterEnabled(true);

    LinkedList<Edge> addedEdges = new LinkedList<Edge>();
    //layout outer:
    for(int i=0;i<outer.size()-1;i++){
      //connect the outer nodes
      addedEdges.add(g.createEdge(outer.get(i), outer.get(i + 1)));
    }

    NodeMap nodeMap = g.createNodeMap();
    for(Node n : outer){
      nodeMap.setBool(n, true);
    }
    for(Node n : inner){
      nodeMap.setBool(n, false);
    }

    g.addDataProvider(Layouter.SELECTED_NODES, nodeMap);
    layouter.setAutomaticRadius(false);
    layouter.setFixedRadius(radius);
    layouter.doLayout(g);

    for(Node n : outer){
      g.setSelected(n,true);
    }
    Rectangle2D outerBox = getBoundingBoxOf(g.selectedNodes(), g);
    g.unselectNodes();


    for(Edge e : addedEdges){
      g.removeEdge(e);
    }

    nodeMap = g.createNodeMap();
    for(Node n : inner){
      nodeMap.setBool(n, true);
    }
    for(Node n : outer){
      nodeMap.setBool(n, false);
    }

    addedEdges.clear();

    //layout inner:
    for(int i=0;i<inner.size()-1;i++){
      //connect the outer nodes
      addedEdges.add(g.createEdge(inner.get(i), inner.get(i + 1)));
    }

    g.addDataProvider(Layouter.SELECTED_NODES, nodeMap);
    layouter.setAutomaticRadius(false);
    layouter.setFixedRadius(radius / 3);
    layouter.doLayout(g);

    for(Node n : inner){
      g.setSelected(n,true);
    }
    Rectangle2D innerBox = getBoundingBoxOf(g.selectedNodes(), g);
    g.moveNodes(g.selectedNodes(), outerBox.getCenterX() - innerBox.getCenterX() , outerBox.getCenterY() - innerBox.getCenterY());
    g.unselectNodes();

    for(Edge e : addedEdges){
      g.removeEdge(e);
    }
  }

  static Rectangle2D getBoundingBoxOf(NodeCursor nodes, Graph2D g){
    Rectangle2D box = new Rectangle2D.Double();
    for(;nodes.ok();nodes.next()){
      box.add(g.getRealizer(nodes.node()).getBoundingBox());
    }
    return box;
  }


}
